﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class HitRecord
{
    public float t;
    public Vector3 p;
    public Vector3 normal;
    public Material material;
}

public class Hitable
{

    public Hitable() { }
    public virtual bool Hit(Ray r, float t_min, float t_max, ref HitRecord rec)
    {
        return false;
    }
}

public class Sphere : Hitable
{
    public Vector3 center;
    public float radius;
    Material material;
    public Sphere(Vector3 center, float r,Material material=null)
    {
        this.material = material;
        this.center = center;
        this.radius = r;
    }
    public override bool Hit(Ray r, float t_min, float t_max, ref HitRecord rec)
    {
        
        Vector3 oc = r.original - center;
        float a = Vector3.Dot(r.direction, r.direction);
        float b = 2.0f * Vector3.Dot(oc, r.direction);
        float c = Vector3.Dot(oc, oc) - radius * radius;
        //方程是否有根 两个就相交
        float discriminant = b * b - 4 * a * c;
        if (discriminant > 0)
        {
            //计算最靠近射线源的点
            float temp = (-b - Mathf.Sqrt(discriminant)) / a *0.5f;
            if (temp < t_max && temp > t_min)//内部
            {
                rec.t = temp;
                rec.p = r.GetRay(rec.t); //交点
                rec.normal = (rec.p - center)/radius;
                rec.material = material;
                return true;
            }
            //计算远离射线源的点
            temp = (-b + Mathf.Sqrt(discriminant)) / a * 0.5f;
            if (temp < t_max && temp > t_min)
            {
                rec.t = temp;
                rec.p = r.GetRay(rec.t);
                rec.normal = (rec.p - center)/radius; // cacl normal
                rec.material = material;
                return true;
            }
           
        }
        return false;
    }
}

public class HitableList : Hitable
{
    public List<Hitable> list = new List<Hitable>();
    public HitableList() { }
    public HitableList(List<Hitable> list)
    {
        this.list = list;
    }

    public override bool Hit(Ray r, float t_min, float t_max, ref HitRecord rec)
    {
        HitRecord tempRec = new HitRecord();
        bool hit_anything = false;
        float closest_so_far = t_max;
        for (int i = 0; i < list.Count; i++)
        {
            if (list[i].Hit(r, t_min, closest_so_far, ref tempRec))
            {
                hit_anything = true;
                closest_so_far = tempRec.t;
                rec = tempRec;
            }
        }
        return hit_anything;
    }
}
